package com.mach.platform.api.service;

import com.mach.platform.api.domain.Team;
import com.mach.platform.api.repository.AttentRepo;
import com.mach.platform.api.repository.MessageRepo;
import com.mach.platform.api.repository.TeamRepo;
import com.mach.platform.domain.EnergyStruc;
import com.mach.platform.domain.PageVo;
import com.mach.platform.domain.Response;
import com.mach.platform.domain.iot.IotDev;
import com.mach.platform.domain.iot.IotDevParams;
import com.mach.platform.domain.iot.IotSpace;
import com.mach.platform.domain.iot.IotVirtualItem;
import com.mach.platform.repository.EnergyStrucRepo;
import com.mach.platform.repository.IotDevRepo;
import com.mach.platform.repository.IotSpaceRepo;
import com.mach.platform.service.UServ;
import com.mach.platform.util.SqlHelper;
import com.mach.platform.utils.DateUtil;
import com.mach.platform.utils.springdata.Collections3;
import com.mach.platform.utils.springdata.DynamicSpecifications;
import com.mach.platform.utils.springdata.SearchFilter;
//import jdk.nashorn.internal.runtime.options.Option;
import org.apache.commons.lang3.ArrayUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.Pageable;
import org.springframework.data.jpa.domain.Specification;
import org.springframework.stereotype.Service;

import javax.sql.DataSource;
import java.math.BigInteger;
import java.sql.SQLException;
import java.text.ParseException;
import java.util.*;
import java.util.stream.Stream;

@Service
public class MonitorServiceImpl {

    private SqlHelper sqlHelper = null;

    @Qualifier("dataSource")
    @Autowired
    private DataSource dataSource;

    @Autowired
    private IotDevRepo iotDevRepo;

    @Autowired
    private IotSpaceRepo iotSpaceRepo;

    @Autowired
    private TeamRepo teamRepo;

    @Autowired
    private MessageRepo messageRepo;

    @Autowired
    private AttentRepo attentRepo;

    @Autowired
    private EnergyStrucRepo energyRepo;

    /**
     * 获取数据库连接
     * @return
     */
    public SqlHelper getSqlHelper() {
        if (null == sqlHelper) {
            SqlHelper newSqlHelper = SqlHelper.getBySource(dataSource);
            this.sqlHelper = newSqlHelper;
            return newSqlHelper;
        }
        return sqlHelper;
    }


    /**
     * 获取用户对应的站房数据：包括空压，制冷，供水，供电，燃气，蒸汽
     * @param openId 用户openId
     * @return
     */
    public Map[] stationList(String openId) {
        List<Team> teamList = teamRepo.findByOpenId(openId);
        Map[] result = new Map[teamList.size()];
        for (int i = 0; i < teamList.size(); i++) {
            Team team = teamList.get(i);
            Map map = new HashMap();
            map.put("id", team.getStationId());
            map.put("name", team.getTeamName());
            result[i] = map;
        }
        return result;
    }


    /**
     * 查询能源站房--工艺控制--空压机房--的主机菜单列表
     * @param id 站房id
     * @return
     */
    public Map[] getStationMenu(Long id) throws SQLException {
        SqlHelper sqlHelper = getSqlHelper();
        String sql = "select id, name from iot_space where parent_id = (select id from iot_space where parent_id =" +
                "(select id from iot_space where parent_id = " + id + " and type = 101) and type = 500)";
        List<Map<String, Object>> resultMap = sqlHelper.queryList(sql);
        Map[] result = new Map[resultMap.size()];
        for (int i = 0; i < resultMap.size(); i++) {
            Map map = resultMap.get(i);
            Map newMap = new HashMap<String, Object>();
            newMap.put("id", map.get("id"));
            newMap.put("name", map.get("name"));
            result[i] = newMap;
        }
        return result;
    }


    /**
     * 验证机组下的第一个控制设备是否配置了必要的属性和参数
     * @param id 机组菜单id
     * @return
     */
    public Response checkItemParams(Long id) {
        IotDev iotDev = iotDevRepo.findIotDevBySpaceId(id, 10);
        if (null == iotDev) {
            return Response.error("该机组控制设备下没有挂设备");
        }
        List<IotVirtualItem> itemList = iotDev.getVirtualItems();
        List<IotDevParams> devParams = iotDev.getDevParams();
        List<String> virItems = Collections3.extractToList(itemList, "name");
        List<String> items = Arrays.asList(new String[] {"控制模式", "模式选择", "上限", "下限"});
        // 查询必要的属性配置
        for (String item : items) {
            if (!virItems.contains(item)) {
                return Response.error("当前机组的控制设备没有配置必要的属性");
            }
        }
        // 找到必要的参数
        Optional<IotDevParams> a = devParams.stream().filter((params) -> params.getName().equals("range")).findFirst();
        if (!a.isPresent()) {
            return Response.error("当前机组的控制设备没有配置上下线范围参数：range");
        }
        return Response.ok(iotDev);
    }


    /**
     * 查询机房下第一个控制设备的实时数据
     * @param openId 小程序用户openId
     * @param id 机组菜单id
     * @param iotDev 控制设备
     * @return
     */
    public Map controlDeviceData(String openId, Long id, IotDev iotDev) {
        List<IotVirtualItem> itemList = iotDev.getVirtualItems();
        // 开始查询控制设备的实时数据
        List<Map> resultData = iotDevRepo.devItemsCurData(iotDev.getId());
        List<Map> attentData = attentRepo.findByOpenIdDevGroupId(openId, id);
        Map resultMap = new HashMap(); // 返回结果Map
        // 添加机组设备id和关注状态
        int attentStatus = 0;
        if (Collections3.isNotEmpty(attentData)) {
            attentStatus = 1;
        }
        resultMap.put("id", iotDev.getId());
        resultMap.put("attentStatus", attentStatus);

        // 添加设备的某些固定属性数据，需要在后台配置
        String[] itemNames = {"控制模式", "模式选择", "上限", "下限"};
        String[] itemKeys = {"controlMode", "modeChoose", "onLimit", "upLimit"};
        for (int i = 0; i < itemNames.length; i++) {
            Object value = null;
            for (Map map : resultData) {
                if (itemNames[i].equals(map.get("data_type"))) {
                    value = map.get("dvalue");
                    break;
                }
            }
            resultMap.put(itemKeys[i], value);
        }
        List<IotDevParams> iotDevParams = iotDev.getDevParams();
        IotDevParams devParams = iotDevParams.stream().filter((params) -> params.getName().equals("range")).findFirst().get();
        String[] limitRange = devParams.getTextValue().split("-");
        // 添加上下限范围
        resultMap.put("start", Float.parseFloat(limitRange[0]));
        resultMap.put("end", Float.parseFloat(limitRange[1]));

        // 先从虚拟设备属性里面找到除 1.控制模式 2.模式选择 3.上限 4.下限 之外的其他两个属性
        List<String> controlItems = Arrays.asList(new String[]{"控制模式", "模式选择", "上限", "下限"});
        List<String> devItemList = new ArrayList();
        for (int i = 0; i < itemList.size(); i++) {
            IotVirtualItem item = itemList.get(i);
            if (devItemList.size() < 2 && !controlItems.contains(item.getName())) {
                devItemList.add(item.getName());
            }
        }
        // 添加最后两个属性数据
        int length = devItemList.size();
        Map[] data = new Map[length];
        for (int i = 0; i < length; i++) {
            Object value = null;
            String unit = null;
            for (Map map : resultData) {
                if (devItemList.get(i).equals(map.get("data_type"))) {
                    value = map.get("dvalue");
                    unit = (String) map.get("unit");
                    break;
                }
            }
            Map map = new HashMap();
            map.put("name", devItemList.get(i));
            map.put("value", value);
            map.put("unit", unit);
            data[i] = map;
        }
        resultMap.put("other", data);
        return resultMap;
    }


    /**
     * 查询机房下机组设备的实时数据
     * @param pageable
     * @param id
     * @param openId
     * @return
     */
    public PageVo unitDeviceData(Pageable pageable, Long id, String openId) {
        IotSpace iotSpace = iotSpaceRepo.findFirstByParentIdAndType(id, 11);
        // 构造JPA分页参数
        Map params = new HashMap();
        params.put("iotSpace.id_eq", iotSpace.getId());
        Specification specification = DynamicSpecifications.bySearchFilter(SearchFilter.parse(params).values(), IotDev.class);
        Page<IotDev> pageInfo = iotDevRepo.findAll(specification, pageable);
        List<IotDev> iotDevList = pageInfo.getContent();
        List<Long> devIds = Collections3.extractToList(iotDevList, "id");
        List<Map> curData = iotDevRepo.findByDevIdsItem(devIds, "运行状态");
        List<Map> attendData = attentRepo.findByOpenIdDevIds(openId, devIds);

        // 开始组装前端数据
        Map[] result = new Map[iotDevList.size()];
        for (int i = 0; i < iotDevList.size(); i++) {
            IotDev iotDev = iotDevList.get(i);
            Map resultMap = new HashMap();
            Object runStatus = 3; // 默认是离线状态
            int attendStatus = 0; // 0：没关注 1：已关注
            // 判断是否含有实时数据
            for (int j = 0; j < curData.size(); j++) {
                Map map = curData.get(j);
                if (iotDev.getId().toString().equals(map.get("dev_id").toString())) {
                    runStatus = map.get("dvalue");
                    break;
                }
            }
            // 判断是否关注了设备
            for (Map map : attendData) {
                if (iotDev.getId().toString().equals(map.get("dev_id").toString())) {
                    attendStatus = 1;
                    break;
                }
            }
            resultMap.put("runStatus", runStatus);
            resultMap.put("devId", iotDev.getId());
            resultMap.put("devName", iotDev.getName());
            resultMap.put("attendStatus", attendStatus);
            result[i] = resultMap;
        }
        return new PageVo(pageInfo.getNumber(), pageInfo.getSize(), pageInfo.getTotalElements(), pageInfo.getTotalPages(), result);
    }


    /**
     * 修改控制设备的上限值
     * @param id 设备的id
     * @param value 上限值
     * @return
     */
    public void updateOnLimit(Long id, double value) {

    }


    /**
     * 修改控制设备的下限值
     * @param id 设备id
     * @param value 下限值
     * @return
     */
    public void updateUpLimit(Long id, double value) {

    }


    /**
     * 查询站房分管下机组分页的设备属性数据集合
     * @param pageable
     * @param id
     * @return
     */
    public PageVo partManageDevice(Pageable pageable, Long id) {
        IotSpace iotSpace = iotSpaceRepo.findFirstByParentIdAndType(id, 11);
        // 构造JPA分页参数
        Map params = new HashMap();
        params.put("iotSpace.id_eq", iotSpace.getId());
        Specification specification = DynamicSpecifications.bySearchFilter(SearchFilter.parse(params).values(), IotDev.class);

        Page<IotDev> pageInfo = iotDevRepo.findAll(specification, pageable);
        List<IotDev> iotDevList = pageInfo.getContent();
        List<Integer> devIds = Collections3.extractToList(iotDevList, "id");
        List<Map> resultData = iotDevRepo.curDataByDevIds(devIds);
        // 开始组装前端数据
        Map[] result = new Map[iotDevList.size()]; // 返回的前端result数组
        String[] itemKeys = new String[]{"controlMode", "runStatus", "modeChoose", "valueOpen"}; // 和属性名称对应的属性key
        String[] itemNames = new String[]{"控制模式", "运行状态", "模式选择", "阀门开度"}; // 已经确定的属性名称，后端进行配置
        for (int i = 0; i < iotDevList.size(); i++) {
            IotDev iotDev = iotDevList.get(i);
            List<IotVirtualItem> virtualItems = iotDev.getVirtualItems();
            Map devData = new HashMap();
            // 组装已经确定名称的属性数据
            for (int j = 0; j < itemNames.length; j++) {
                Object value = null;
                for (Map map : resultData) {
                    if (iotDev.getId().toString().equals(map.get("dev_id").toString()) && itemNames[j].equals(map.get("data_type"))) {
                        value = map.get("dvalue");
                        break;
                    }
                }
                // 组装每一个属性数据
                devData.put(itemKeys[j], value);
            }
            // 找到剩下的前面两个属性名称(流量/压力)
            List<String> others = new ArrayList<>();
            for (IotVirtualItem item : virtualItems) {
                if (others.size() == 2) {
                    break;
                }
                if (!ArrayUtils.contains(itemNames, item.getName())) {
                    others.add(item.getName());
                }
            }
            Map[] itemArr = new Map[others.size()];
            for (int k = 0; k < others.size(); k++) {
                String item = others.get(k);
                Object value = null;
                Object unit = null;
                for (Map map : resultData) {
                    if (iotDev.getId().toString().equals(map.get("dev_id").toString()) && item.equals(map.get("data_type"))) {
                        value = map.get("dvalue");
                        unit = map.get("unit");
                        break;
                    }
                }
                // 组装剩下other数据
                Map map = new HashMap();
                map.put("name", item);
                map.put("value", value);
                map.put("unit", unit);
                itemArr[k] = map;
            }
            devData.put("other", itemArr);
            // 组装全部设备的全部属性数据
            Map device = new HashMap();
            device.put("id", iotDev.getId());
            device.put("name", iotDev.getName());
            device.put("itemData", devData);
            result[i] = device;
        }
        return new PageVo(pageInfo.getNumber(), pageInfo.getSize(), pageInfo.getTotalElements(), pageInfo.getTotalPages(), result);
    }


    /**
     * 查询设备的报警次数，运维次数，点检次数
     * @param devId
     * @return
     */
    public Map maintainData(Long devId) {
        List<Map> maintainData = messageRepo.getMaintainDataByDevId(devId);
        Map result = new HashMap();
        for (int i = 1; i <= 3; i++) {
            int statNum = 0; // 统计数量
            for (Map map : maintainData) {
                int hurdles = (int) map.get("hurdles");
                int num = ((BigInteger) map.get("num")).intValue();
                if (i == hurdles) {
                    statNum = num;
                }
            }
            if (i == 1) {
                result.put("alarmNum", statNum);
            }
            if (i == 2) {
                result.put("maintainNum", statNum);
            }
            if (i == 3) {
                result.put("checkNum", statNum);
            }
        }
        return result;
    }


    /**
     * 查询设备的控制模式和运行状态
     * @param devId 设备id
     * @return
     */
    public Map modeRunStatus(Long devId) {
        List<Map> resultData = iotDevRepo.devItemsCurData(devId);
        // 添加设备的控制属性数据
        Map itemMap = new HashMap();
        itemMap.put("controlMode", "控制模式");
        itemMap.put("runStatus", "运行状态");
        Map resultMap = new HashMap();
        for (Object key : itemMap.keySet()) {
            int value = 3; // 默认是离线状态
            for (Map map : resultData) {
                if (itemMap.get(key).equals(map.get("data_type"))) {
                    value = new Double((Double) map.get("dvalue")).intValue();
                    break;
                }
            }
            resultMap.put(key, value);
        }
        return resultMap;
    }


    /**
     * 查询设备所有属性的数据
     * @param devId
     * @return
     */
    public Map[] devItemsData(Long devId) {
        List<Map> resultMap = iotDevRepo.devItemsCurData(devId);
        Map[] resultArr = new Map[resultMap.size()];
        for (int i = 0; i < resultMap.size(); i++) {
            Map result = resultMap.get(i);
            Map map = new HashMap<String, Object>();
            map.put("name", result.get("data_type"));
            map.put("value", result.get("dvalue"));
            map.put("unit", result.get("unit"));
            resultArr[i] = map;
        }
        return resultArr;
    }


    /**
     * 查询设备某个属性当天的数据
     * @param devId
     * @param name
     * @return
     */
    public Map devItemData(Long devId, String name) throws ParseException {
        String startTime = DateUtil.getStartOfDayInYMDHMS();
        String endTime = DateUtil.getEndOfDayInYMDHMS();
        List<Map> resultMap = iotDevRepo.findDevItemData(devId, name, startTime, endTime);

        String currDate = DateUtil.getYmd();
        String[] xAxis = UServ.getTimeArrByTime(currDate);
        Object[] series = new Object[xAxis.length];
        for (int i = 0; i < xAxis.length; i++) {
            double value = 0;
            for (int j = 0; j < resultMap.size(); j++) {
                Map map = resultMap.get(j);
                if (xAxis[i].equals(map.get("time"))) {
                    value = (double) map.get("value");
                    break;
                }
            }
            series[i] = value;
        }
        Map result = new HashMap<String, Object>();
        result.put("xAxis", xAxis);
        result.put("series", series);
        return result;
    }

    /**
     * 根据站房id和节点类型id获取工艺能效空间下的设备
     * @param id
     * @param type
     * @return
     */
    public String getIotDevId(Long id, int type) {
        return "(select id from iot_dev where space_id = (select id from iot_space where parent_id =" +
                " (select id from iot_space where parent_id = " + id + " and type = 102) and type = " + type + ") limit 1)";
    }


    /**
     * 查询站房指定月份的供出，用量，损耗的统计数据
     * @param id 站房id
     * @param time 时间
     * @return
     */
    public Map stationDosage(Long id, String  time) {
        Map resultMap = new HashMap<String, Object>();
        SqlHelper sqlHelper = getSqlHelper();
        // 查询站房-工艺能效-总量/一区的节点id
        String totalDevId = getIotDevId(id, 400); // 总量栏
        String oneZoneDevId = getIotDevId(id, 401); // 一区
        String supplyEnergySql = "select sum(dvalue) value from iot_dev_data_win where dev_id = " + totalDevId + " and data_type = '总冷量' and the_time like '" + time + "%'";
        String useEnergySql = "select sum(dvalue) value from iot_dev_data_win where dev_id = " + oneZoneDevId + " and data_type like '%用气' and the_time like '" + time + "%'";
        try {
             Map supplyResult = sqlHelper.queryOne(supplyEnergySql);
             Map useResult = sqlHelper.queryOne(useEnergySql);
             double supplyValue = 0;
             double useValue = 0;
             if (supplyResult.get("value") != null) {
                 supplyValue = (double) supplyResult.get("value");
             }
             if (useResult.get("value") != null) {
                 useValue = (double) useResult.get("value");
             }
             resultMap.put("supplyEnergy", supplyValue);
             resultMap.put("useEnergy", useValue);
             resultMap.put("lossEnergy", supplyValue - useValue);
        } catch (SQLException e) {
            e.printStackTrace();
        }
        return resultMap;
    }


    /**
     * 获取指定时间N个月前后的时间：yyyy-MM
     * @param date 指定时间
     * @param month 月份个数
     * @param beforeAfter 时间前后
     * @return
     */
    public String getMonthBeforeAfter(String date, int month, String beforeAfter) throws ParseException {
        String format = "yyyy-MM";
        Date time = DateUtil.getDateByStrTime(date, format);
        Calendar calendar = Calendar.getInstance();
        calendar.setTime(time);
        if (beforeAfter.equals("before")) {
            calendar.add(Calendar.MONTH, -month);
        } else {
            calendar.add(Calendar.MONTH, +month);
        }
        return DateUtil.getStringDate(calendar.getTime(), format);
    }


    /**
     * 获取指定时间往前推半年的yyyy-MM集合
     * @param time 时间
     * @return
     */
    public Object[] getBeforeSixMonthArr(String time) throws ParseException {
        List timeArr = new ArrayList<String>();
        for (int i = 5; i > 0; i--) {
            String date = getMonthBeforeAfter(time, i, "before");
            timeArr.add(date);
        }
        timeArr.add(time); // 添加当前月份时间
        return timeArr.toArray();
    }


    /**
     * 组装前端数据
     * @param sql
     * @param xAxis
     * @return
     */
    public Object[] getObjectData(String sql, Object[] xAxis) {
        Object[] newSeries = new Object[xAxis.length];
        try {
            SqlHelper sqlHelper = getSqlHelper();
            List<Map<String, Object>> result = sqlHelper.queryList(sql);
            for (int i = 0; i < xAxis.length; i++) {
                double value = 0;
                for (Map map : result) {
                    if (xAxis[i].equals(map.get("time"))) {
                        value = (double) map.get("value");
                        break;
                    }
                }
                newSeries[i] = value;
            }
        } catch (SQLException e) {
            e.printStackTrace();
        }
        return newSeries;
    }


    /**
     * 查询站房指定类型最近半年的数据
     * @param id 站房id
     * @param dataType 数据类型
     * @param time 时间
     * @return
     */
    public Map  dosageTrend(Long id, int dataType, String time) throws ParseException {
        String startTime = getMonthBeforeAfter(time, 5, "before");
        String endTime = getMonthBeforeAfter(time, 1, "after");
        // 查询站房-工艺能效-总量的节点id
        String totalDevId = getIotDevId(id, 400); // 总量栏
        String oneZoneDevId = getIotDevId(id, 401); // 一区
        String supplyEnergySql = "select DATE_FORMAT(the_time,'%Y-%m') time, sum(dvalue) value from iot_dev_data_win" +
                " where dev_id = " + totalDevId + " and data_type = '总冷量' and the_time >= '" + startTime + "' and the_time < '" + endTime + "' group by time";
        String useEnergySql = "select DATE_FORMAT(the_time,'%Y-%m') time, sum(dvalue) value from iot_dev_data_win" +
                " where dev_id = " + oneZoneDevId + " and data_type like '%用气' and the_time >= '" + startTime + "' and the_time < '" + endTime + "' group by time";
        Object[] monthArr = getBeforeSixMonthArr(time);
        Object[] xAxis = monthArr;
        Object[] series = new Object[monthArr.length];

        Map resultMap = new HashMap<String, Object>();
        resultMap.put("xAxis", xAxis);
        if (dataType == 1) {
            series = getObjectData(supplyEnergySql, xAxis);
        } else if (dataType == 2) {
            series = getObjectData(useEnergySql, xAxis);
        } else if (dataType == 3) {
            Object[] supplySeries = getObjectData(supplyEnergySql, xAxis);
            Object[] useSeries = getObjectData(useEnergySql, xAxis);
            for (int i = 0; i < supplySeries.length; i++) {
                series[i] = (double) supplySeries[i] - (double) useSeries[i];
            }
        }
        resultMap.put("series", series);
        return resultMap;
    }


    /**
     * 查询用能排行榜数据
     * @param id
     * @param time
     * @return
     */
    public Map[] dosageRanking(Long id, String time) {
        Map[] resultArr = null;
        String devId = getIotDevId(id, 401); // 工艺能效一区设备id
        String sql = "select data_type name, sum(dvalue) value from iot_dev_data_win where dev_id = " + devId
                + " and data_type in (select name from iot_virtual_item where dev_id = " + devId + " and name like '%用气')"
                + " and the_time like '" + time + "%' group by data_type order by value";
        SqlHelper sqlHelper = getSqlHelper();
        try {
            List<Map<String, Object>> result = sqlHelper.queryList(sql);
            resultArr = new Map[result.size()];
            for (int i = 0; i < result.size(); i++) {
                Map resultMap = result.get(i);
                Map map = new HashMap<String, Object>();
                map.put("name", resultMap.get("name"));
                map.put("dosage", resultMap.get("value"));
                map.put("price", resultMap.get("price"));
                map.put("rank", i + 1);
                resultArr[i] = map;
            }
        } catch (SQLException e) {
            e.printStackTrace();
        }
        return resultArr;
    }


}
